//////////////////////////////////////////////////////
// 程序名称：建立面表、环表、顶点表三表结构。画出三维物体的消隐图
// 功 能：自动生成，待补充
// 编译环境：Visual Studio 2017，EasyX_20190219(beta)
// 作 者：xyqlx<mxxyqlx@qq.com>
// 最后修改：2019-4-11
#include <conio.h>
#include <graphics.h>
#include <cmath>
#include <cstring>
#include <vector>

const float feps = 1e-8f;
int sgn(float f) { return f < -feps ? -1 : (f < feps ? 0 : 1); }
IMAGE img(640, 480);

//3D
class Vector3
{
  public:
	float mat[4];
	Vector3() : Vector3(0.0f, 0.0f, 0.0f) {}
	Vector3(float x, float y, float z, float w = 1.0f)
	{
		mat[0] = x;
		mat[1] = y;
		mat[2] = z;
		mat[3] = w;
	}
	Vector3(const Vector3 &rhs)
	{
		mat[0] = rhs.mat[0];
		mat[1] = rhs.mat[1];
		mat[2] = rhs.mat[2];
		mat[3] = rhs.mat[3];
	}
	const Vector3 &operator=(const Vector3 &rhs)
	{
		mat[0] = rhs.mat[0];
		mat[1] = rhs.mat[1];
		mat[2] = rhs.mat[2];
		mat[3] = rhs.mat[3];
		return *this;
	}
	float Norm() const { return sqrt(mat[0] * mat[0] + mat[1] * mat[1] + mat[2] * mat[2]); }
	bool Normalize()
	{
		float r = Norm();
		if (sgn(r))
		{
			mat[0] /= r;
			mat[1] /= r;
			mat[2] /= r;
			return 1;
		}
		return 0;
	}
};
Vector3 operator+(const Vector3 &lhs, const Vector3 &rhs)
{
	return Vector3(lhs.mat[0] + rhs.mat[0], lhs.mat[1] + rhs.mat[1], lhs.mat[2] + rhs.mat[2], lhs.mat[3]);
}
Vector3 operator-(const Vector3 &lhs, const Vector3 &rhs)
{
	return Vector3(lhs.mat[0] - rhs.mat[0], lhs.mat[1] - rhs.mat[1], lhs.mat[2] - rhs.mat[2], lhs.mat[3]);
}
Vector3 operator-(const Vector3 &rhs)
{
	return Vector3(-rhs.mat[0], -rhs.mat[1], -rhs.mat[2], rhs.mat[3]);
}
float Distance(const Vector3 &lhs, const Vector3 &rhs)
{
	return sqrt(pow(lhs.mat[0] - rhs.mat[0], 2) + pow(lhs.mat[1] - rhs.mat[1], 2) + pow(lhs.mat[2] - rhs.mat[2], 2));
}

class Transform3
{
  public:
	float mat[4][4];
	Transform3()
	{
		memset(mat, 0, sizeof(mat));
		mat[0][0] = mat[1][1] = mat[2][2] = mat[3][3] = 1.0f;
	}
	Transform3(const Transform3 &rhs)
	{
		memcpy(mat, rhs.mat, sizeof(mat));
	}
	Transform3 &operator=(const Transform3 &rhs)
	{
		memcpy(mat, rhs.mat, sizeof(mat));
	}
	const Transform3 &operator*=(const Transform3 &rhs)
	{
		float res[4][4];
		memset(res, 0, sizeof(res));
		for (int i = 0; i < 4; ++i)
		{
			for (int j = 0; j < 4; ++j)
			{
				for (int k = 0; k < 4; ++k)
				{
					res[i][j] += mat[i][k] * rhs.mat[k][j];
				}
			}
		}
		memcpy(mat, res, sizeof(mat));
		return *this;
	}
};
Transform3 operator*(const Transform3 &lhs, const Transform3 &rhs)
{
	Transform3 temp(lhs);
	temp *= rhs;
	return temp;
}
Transform3 TMultiply(const Transform3 &lhs, const Transform3 &rhs)
{
	return lhs * rhs;
}
Vector3 operator*(const Vector3 &lhs, const Transform3 &rhs)
{
	Vector3 res(0.0f, 0.0f, 0.0f, 0.0f);
	for (int i = 0; i < 4; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			res.mat[i] += lhs.mat[j] * rhs.mat[j][i];
		}
	}
	return res;
}
Vector3 VMultiply(const Vector3 &lhs, const Transform3 &rhs)
{
	return lhs * rhs;
}
const Vector3 &operator*=(Vector3 &lhs, const Transform3 &rhs)
{
	float mat[4];
	memset(mat, 0, sizeof(mat));
	for (int i = 0; i < 4; ++i)
	{
		for (int j = 0; j < 4; ++j)
		{
			mat[i] += lhs.mat[j] * rhs.mat[j][i];
		}
	}
	memcpy(lhs.mat, mat, sizeof(mat));
	return lhs;
}
class Transform3Factory
{
  public:
	Transform3 Trivial()
	{
		Transform3 res;
		return res;
	}
	Transform3 Translation(const Vector3 &d)
	{
		Transform3 res;
		res.mat[3][0] = d.mat[0];
		res.mat[3][1] = d.mat[1];
		res.mat[3][2] = d.mat[2];
		return res;
	}
	Transform3 Translation(float dx, float dy, float dz)
	{
		Transform3 res;
		res.mat[3][0] = dx;
		res.mat[3][1] = dy;
		res.mat[3][2] = dz;
		return res;
	}
	Transform3 Rotation(Vector3 angle)
	{
		//rebuild
		Transform3 res;
		if (angle.Normalize())
		{
			res.mat[0][0] = res.mat[1][1] = angle.mat[0];
			res.mat[0][1] = angle.mat[1];
			res.mat[1][0] = -angle.mat[1];
		}
		return res;
	}
	Transform3 Rotation(float angle)
	{
		//rebuild
		Transform3 res;
		float c = cos(angle);
		float s = sin(angle);
		res.mat[0][0] = res.mat[1][1] = c;
		res.mat[0][1] = s;
		res.mat[1][0] = -s;
		return res;
	}
	Transform3 Scaling(const Vector3 &s)
	{
		Transform3 res;
		res.mat[0][0] = s.mat[0];
		res.mat[1][1] = s.mat[1];
		res.mat[2][2] = s.mat[2];
		return res;
	}
	Transform3 Scaling(float sx, float sy)
	{
		Transform3 res;
		res.mat[0][0] = sx;
		res.mat[1][1] = sy;
		res.mat[2][2] = sy;
		return res;
	}
	Transform3 SymmetryX()
	{
		Transform3 res;
		res.mat[1][1] = -1;
		res.mat[2][2] = -1;
		return res;
	}
	Transform3 SymmetryY()
	{
		Transform3 res;
		res.mat[0][0] = -1;
		res.mat[2][2] = -1;
		return res;
	}
	Transform3 SymmetryZ()
	{
		Transform3 res;
		res.mat[0][0] = -1;
		res.mat[1][1] = -1;
		return res;
	}
	Transform3 Shear(float sx, float sy)
	{
		//rebuild
		Transform3 res;
		res.mat[1][0] = sx;
		res.mat[0][1] = sy;
		return res;
	}
	Transform3 SymmetryLine(Vector3 v1, Vector3 v2)
	{
		//rebuild
		Transform3 res;
		if (!sgn(v1.mat[0] - v2.mat[0]))
		{
			if (!sgn(v1.mat[1] - v2.mat[1]))
			{
				return res;
			}
			res *= Translation(-v1.mat[0], 0, 0);
			res *= SymmetryY();
			res *= Translation(v1.mat[0], 0, 0);
			return res;
		}
		else if (!sgn(v1.mat[1] - v2.mat[1]))
		{
			res *= Translation(0, 0, -v1.mat[1]);
			res *= SymmetryX();
			res *= Translation(0, 0, v1.mat[1]);
			return res;
		}
		res *= Translation(-v1);
		res *= Rotation((v2 - v1) * SymmetryX());
		res *= SymmetryX();
		res *= Rotation(v2 - v1);
		res *= Translation(v1);
		return res;
	}
};
class ViewFactory{
public:
	Transform3 FrontView(){
		Transform3 res;
		res.mat[1][1] = 0;
		return res;
	}
	Transform3 SideView(float x0){
		Transform3 res;
		res.mat[0][0] = 0;
		res.mat[1][1] = 0;
		res.mat[1][0] = -1;
 		res.mat[3][0] = -x0;
		return res;
	}
	Transform3 TopView(float z0){
		Transform3 res;
		res.mat[1][1] = 0;
		res.mat[2][2] = 0;
		res.mat[1][2] = -1;
 		res.mat[3][2] = -z0;
		return res;
	}
	Transform3 IsometricView(){
		Transform3 res;
		res.mat[0][0] = 0.707f;
		res.mat[0][2] = -0.408f;
		res.mat[1][0] = -0.707f;
		res.mat[1][2] = -0.408f;
		res.mat[2][2] = 0.8165f;
		return res;
	}
};
class Primitive
{
  public:
	const Primitive& operator=(const Primitive& rhs){
		vertices = rhs.vertices;
		indices = rhs.indices;
		return *this;
	}
	Primitive(){}
	Primitive(const Primitive& rhs):vertices(rhs.vertices),indices(rhs.indices){}
	std::vector<Vector3> vertices;
	std::vector<int> indices;
};
const Primitive &operator*=(Primitive &lhs, const Transform3 &rhs)
{
	for (auto &e : lhs.vertices)
		e *= rhs;
	return lhs;
}
Primitive operator*(const Primitive& lhs, const Transform3 &rhs){
	Primitive res(lhs);
	res *= rhs;
	return res;
}
void DrawPrimitiveXZ(const Primitive& rhs, Vector3 center){
	Vector3 pcenter;
	for (std::vector<Vector3>::const_iterator it = rhs.vertices.begin(); it != rhs.vertices.end(); ++it)
		pcenter = pcenter + *it;
	pcenter.mat[0] /= rhs.vertices.size();
	pcenter.mat[2] /= rhs.vertices.size();
	pcenter.mat[1] = pcenter.mat[2];
	center = center - pcenter;
	for (std::vector<int>::const_iterator it = rhs.indices.begin(); it != rhs.indices.end(); ++it) {
		int start = *it;
		++it;
		int past = *it;
		//判断多边形的方向
		std::vector<int>::const_iterator nit = it;
		++nit;
		bool isHidden((rhs.vertices[past].mat[2] - rhs.vertices[start].mat[2]) * (rhs.vertices[*nit].mat[0] - rhs.vertices[past].mat[0]) - (rhs.vertices[past].mat[0] - rhs.vertices[start].mat[0]) * (rhs.vertices[*nit].mat[2] - rhs.vertices[past].mat[2]) < 0);
		if(!isHidden)
				line(rhs.vertices[start].mat[0] + center.mat[0], rhs.vertices[start].mat[2] + center.mat[1], rhs.vertices[past].mat[0] + center.mat[0], rhs.vertices[past].mat[2] + center.mat[1]);
		for (; past != start; ++it) {
			if(!isHidden)
				line(rhs.vertices[past].mat[0] + center.mat[0], rhs.vertices[past].mat[2] + center.mat[1], rhs.vertices[*it].mat[0] + center.mat[0], rhs.vertices[*it].mat[2] + center.mat[1]);
			past = *it;
		}
		if(it==rhs.indices.end())
			break;
		--it;
	}
}
void Display()
{
	Primitive primitive;
	ViewFactory viewFactory;
	Transform3Factory tranFactory;
	//初始化
	primitive.vertices = {Vector3(0,0,0),Vector3(0,0,100),Vector3(0,200,0),Vector3(0,200,100),Vector3(150,0,0),Vector3(150,0,100),Vector3(150,200,0),Vector3(150,200,100)};
	primitive.indices = {0,1,3,2,0,4,6,7,5,4,0,4,5,1,0,2,3,7,6,2,0,2,6,4,0,1,5,7,3,1};
	//开始绘图
	DrawPrimitiveXZ(primitive * viewFactory.IsometricView() * tranFactory.SymmetryY(), Vector3(320, 240, 0));
	SetWorkingImage();
	putimage(0, 0, &img, SRCCOPY);
}
int main()
{
	// 创建绘图窗口，大小为 640x480 像素
	initgraph(640, 480);
	//填充背景为白色
	setbkcolor(WHITE);
	cleardevice();
	//坐标轴
	SetWorkingImage(&img);
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(GREEN);
	line(0, 240, 640, 240);
	line(320, 0, 320, 480);
	//开始绘制
	setlinecolor(RED);
	Display();
	//结束绘制
	_getch();	 // 按任意键继续
	closegraph(); // 关闭绘图窗口
	return 0;
}